package com.lvmama.search.spider.worker;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.lvmama.search.spider.config.ContentFetchConfig;
import com.lvmama.search.spider.config.Context;
import com.lvmama.search.spider.config.FetchResult;
import com.lvmama.search.spider.proxy.ProxyIp;
import com.lvmama.search.spider.proxy.ProxyManager;

public class DefaultContentFetcher implements IContentFetcher{

	private static Log log=LogFactory.getLog(DefaultContentFetcher.class);
	
	public FetchResult getPageContent(ContentFetchConfig contentFetchConfig){
		HttpRequestBase method = null;
		FetchResult result = null;
		int count = Math.max(0, contentFetchConfig.getRetryPolicy().maxRetry()) + 1;
		for (int i = 0; i < count; i++) {
			if ("post".equals(contentFetchConfig.getMethod())) {
				method = new HttpPost(contentFetchConfig.getUrl());
				if(contentFetchConfig.getParameters()!=null&&!contentFetchConfig.getParameters().isEmpty()) {
			        try {
			        	List<NameValuePair> parameterList = new ArrayList<NameValuePair>();  
			        	for (Map.Entry<String, String> entry : contentFetchConfig.getParameters().entrySet()) {
			        		parameterList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));  
			        	}
						((HttpPost)method).setEntity(new UrlEncodedFormEntity(parameterList,"UTF-8"));
					} catch (UnsupportedEncodingException e) {
						log.error("encode error ",e);
					} 
				}
			} else {
				StringBuilder builder=new StringBuilder(contentFetchConfig.getUrl());
				if(contentFetchConfig.getParameters()!=null&&!contentFetchConfig.getParameters().isEmpty()) {
					if(builder.indexOf("?")>=0) {
						builder.append("&");
					}else {
						builder.append("?");
					}
			        try {
			        	boolean first=true;
			        	for (Map.Entry<String, String> entry : contentFetchConfig.getParameters().entrySet()) {
			        		if(!first) {
			        			builder.append("&");
			        		}else {
			        			first=true;
			        		}
			        		builder.append(entry.getKey()+"="+URLEncoder.encode(entry.getValue(), "UTF-8")); 
			        	}
					} catch (UnsupportedEncodingException e) {
						log.error("encode error ",e);
					} 
				}
				method = new HttpGet(builder.toString());
			}
			if (contentFetchConfig.getHeader() != null) {
				for (Map.Entry<String, String> entry : contentFetchConfig.getHeader().entrySet()) {
					method.addHeader(entry.getKey(), entry.getValue());
				}
			}
			RequestConfig.Builder builder = RequestConfig.custom().setSocketTimeout(contentFetchConfig.getSoTimeout())
					.setConnectTimeout(contentFetchConfig.getConTimeout());
			if(contentFetchConfig.isUseProxy()||contentFetchConfig.getProxyIp()!=null) {
				ProxyIp ip=contentFetchConfig.getProxyIp();
				if(ip==null) {
					ip=ProxyManager.getProxyIp();
				}
				if(ip!=null) {
					builder.setProxy(new HttpHost(ip.getIp(), ip.getPort(), ip.getScheme()));
				}
			}
			RequestConfig config = builder.build();
			method.setConfig(config);
			CloseableHttpResponse response = null;
			 CloseableHttpClient httpClient=null;
			 boolean closeClient=false;
			try {
				result = new FetchResult();
				try {
					httpClient=Context.getHttpClient();
					if(httpClient==null) {
						closeClient=true;
						httpClient=HttpClients.createDefault();
					}
					setDefaultHeader(method);
					response = httpClient.execute(method, Context.getHttpClientContext());
					result.setStatusCode(response.getStatusLine().getStatusCode());
					result.setContent(EntityUtils.toString(response.getEntity()));
					EntityUtils.consume(response.getEntity());
					result.setContentFetchConfig(contentFetchConfig);
					return result;
				} catch (Exception e) {
					log.error("error to fetch data:"+method.getURI().toString(),e);
					result.setError(true);
				}
			} finally {
				if (closeClient&&httpClient!=null) {
					try {
						httpClient.close();
					} catch (Exception e) {
						log.error("httpClient close error:"+e.getMessage(),e);
					}
				}
			
				if (response != null) {
					try {
						response.close();
					} catch (Exception e) {
						log.error("response close error:"+e.getMessage(),e);
					}
				}
			}
			// 如果有重试的情况下，休眠retryInterval时间
			if (i < count - 1 && contentFetchConfig.getRetryPolicy().retryInterval() > 0) {
				try {
					Thread.sleep(contentFetchConfig.getRetryPolicy().retryInterval());
				} catch (InterruptedException e) {
					log.error("sleep Interrupted!"+e.getMessage(),e);
				}
			}
		}
		return result;
	}
	
	private void  setDefaultHeader(HttpRequestBase method) {
		method.setHeader("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
		method.setHeader("accept-encoding", "gzip, deflate, br"); 
		method.setHeader("accept-language", "zh-CN,zh;q=0.9");
		method.setHeader("cache-control", " max-age=0" );
		method.setHeader("dnt", " 1" );
		method.setHeader("user-agent", " Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
	}
}
